package com.hanserwei.han_picture.service.seviceImpl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hanserwei.han_picture.constant.UserConstant;
import com.hanserwei.han_picture.domain.entity.po.User;
import com.hanserwei.han_picture.domain.entity.vo.LoginUserVO;
import com.hanserwei.han_picture.domain.entity.vo.UserVO;
import com.hanserwei.han_picture.domain.exception.ApiException;
import com.hanserwei.han_picture.domain.request.user.UserAddRequest;
import com.hanserwei.han_picture.domain.request.user.UserQueryRequest;
import com.hanserwei.han_picture.domain.request.user.UserUpdateRequest;
import com.hanserwei.han_picture.enums.ResponseCodeEnum;
import com.hanserwei.han_picture.enums.UserRoleEnum;
import com.hanserwei.han_picture.manager.RedisManager;
import com.hanserwei.han_picture.manager.auth.StpKit;
import com.hanserwei.han_picture.mapper.UserMapper;
import com.hanserwei.han_picture.service.UserService;
import com.hanserwei.han_picture.utils.ThrowUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final RedisManager redisManager;

    /**
     * 用户注册
     *
     * @param userAccount   用户账户
     * @param userPassword  用户密码
     * @param checkPassword 校验密码
     * @return 新用户id
     */
    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword) {
        // 1.参数校验
        ThrowUtils.throwIf(StrUtil.hasBlank(userAccount, userPassword, checkPassword), ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        // 2.账户长度校验
        ThrowUtils.throwIf(userAccount.length() < 6, ResponseCodeEnum.INVALID_PARAMETER, "用户账号过短！");
        // 3.密码长度校验
        ThrowUtils.throwIf(userPassword.length() < 8, ResponseCodeEnum.INVALID_PARAMETER, "用户密码过短！");
        // 4.密码一致校验
        ThrowUtils.throwIf(!userPassword.equals(checkPassword), ResponseCodeEnum.INVALID_PARAMETER, "两次输入的密码不一致！");
        // 5.账户不能重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", userAccount);
        Long count = this.getBaseMapper().selectCount(queryWrapper);
        ThrowUtils.throwIf(count > 0, ResponseCodeEnum.USERNAME_ALREADY_EXISTS, "用户已存在！");
        // 6.对密码加密
        String encryptPassword = encryptPassword(userPassword);
        User user = new User();
        user.setUserAccount(userAccount);
        user.setUserPassword(encryptPassword);
        // 设置默认昵称
        user.setUserName("忧忧郁郁大喷菇" + RandomUtil.randomInt(4));
        user.setUserRole(UserRoleEnum.USER.getValue());
        boolean saved = this.save(user);
        ThrowUtils.throwIf(!saved, ResponseCodeEnum.SYSTEM_ERROR, "保存用户失败！");
        return user.getId();
    }

    /**
     * 用户登录
     *
     * @param userAccount  用户账户
     * @param userPassword 用户密码
     * @return LoginUserVO 脱敏后的用户信息
     */
    @Override
    public LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        // 1.参数校验
        ThrowUtils.throwIf(StrUtil.hasBlank(userAccount, userPassword), ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        // 2.账户长度校验
        ThrowUtils.throwIf(userAccount.length() < 6, ResponseCodeEnum.INVALID_PARAMETER, "用户账号过短！");
        // 3.密码长度校验
        ThrowUtils.throwIf(userPassword.length() < 8, ResponseCodeEnum.INVALID_PARAMETER, "用户密码过短！");
        // 4.密码加密
        String encryptPassword = encryptPassword(userPassword);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", userAccount)
                .eq("user_password", encryptPassword);
        User user = this.getBaseMapper().selectOne(queryWrapper);
        ThrowUtils.throwIf(user == null, ResponseCodeEnum.USER_NOT_FOUND, "用户不存在！");
        // 4.保存用户到 session 和 Redis（24小时过期）
        request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, user);
        redisManager.saveUserSession(user.getId(), user, 24);
        // 记录用户登录态到 Sa-token, 便于空间鉴权时使用, 注意保证该用户信息与 SpringSession 中的信息过期时间一致
        StpKit.SPACE.login(user.getId());
        StpKit.SPACE.getSession().set(UserConstant.USER_LOGIN_STATE, user);
        // 5.返回脱敏后的用户信息
        return this.getLoginUserVO(user);
    }

    /**
     * 获取用户信息(脱敏)
     *
     * @param user 用户信息
     * @return 脱敏后的用户信息
     */
    @Override
    public LoginUserVO getLoginUserVO(User user) {
        ThrowUtils.throwIf(user == null, ResponseCodeEnum.USER_NOT_FOUND, "用户不存在！");
        LoginUserVO loginUserVO = new LoginUserVO();
        BeanUtil.copyProperties(user, loginUserVO);
        return loginUserVO;
    }

    /**
     * 获取当前登录用户
     *
     * @param request 用户的登录态
     * @return 当前登录用户
     */
    @Override
    public User getLoginUser(HttpServletRequest request) {
        // 1.先从session获取用户信息
        User currentUser = (User) request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);

        // 2.如果session中没有，尝试从Redis中获取
        if (ObjUtil.isNull(currentUser)) {
            // 这里需要从请求头或其他方式获取用户ID，暂时保持原逻辑
            throw new ApiException(ResponseCodeEnum.UNAUTHORIZED, "用户未登录！");
        }

        // 3.验证用户ID有效性
        long currentUserId = currentUser.getId();
        ThrowUtils.throwIf(currentUserId <= 0, ResponseCodeEnum.USER_NOT_FOUND, "用户不存在！");

        // 4.尝试从Redis获取用户信息（避免频繁查数据库）
        Object redisUser = redisManager.getUserSession(currentUserId);
        if (redisUser instanceof User) {
            // 刷新Redis过期时间
            redisManager.refreshUserSession(currentUserId, 24);
            return (User) redisUser;
        }

        // 5.Redis中没有则从数据库查询，并重新保存到Redis
        currentUser = this.getById(currentUserId);
        ThrowUtils.throwIf(ObjUtil.isNull(currentUser), ResponseCodeEnum.USER_NOT_FOUND, "用户不存在！");
        redisManager.saveUserSession(currentUserId, currentUser, 24);
        return currentUser;
    }

    /**
     * 用户退出登录
     *
     * @param request 登录态
     * @return 是否退出成功
     */
    @Override
    public boolean userLogOut(HttpServletRequest request) {
        // 1.判断用户是否登录
        User currentUser = (User) request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        ThrowUtils.throwIf(ObjUtil.isNull(currentUser), ResponseCodeEnum.UNAUTHORIZED, "用户未登录！");
        // 2.用户已经登录，则退出登录（清除session和Redis）
        request.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE);
        redisManager.deleteUserSession(currentUser.getId());
        return true;
    }

    /**
     * 管理员添加用户
     *
     * @param userAddRequest 用户信息
     * @return 新用户id
     */
    @Override
    public long addUser(UserAddRequest userAddRequest) {
        ThrowUtils.throwIf(userAddRequest == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        User user = new User();
        BeanUtils.copyProperties(userAddRequest, user);
        // 默认密码
        user.setUserPassword(encryptPassword(UserConstant.DEFAULT_PASSWORD));
        boolean saved = this.save(user);
        ThrowUtils.throwIf(!saved, ResponseCodeEnum.SYSTEM_ERROR, "保存用户失败！");
        return user.getId();
    }

    /**
     * 管理员删除用户
     *
     * @param id 用户id
     * @return 是否删除成功
     */
    @Override
    public boolean deleteUser(Long id) {
        ThrowUtils.throwIf(id <= 0, ResponseCodeEnum.INVALID_PARAMETER, "用户id错误！");
        boolean deleted = this.removeById(id);
        ThrowUtils.throwIf(!deleted, ResponseCodeEnum.SYSTEM_ERROR, "删除用户失败！");
        return true;
    }

    /**
     * 管理员更新用户信息
     *
     * @param userUpdateRequest 用户信息
     * @return 是否更新成功
     */
    @Override
    public boolean updateUser(UserUpdateRequest userUpdateRequest) {
        ThrowUtils.throwIf(userUpdateRequest == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        User user = new User();
        BeanUtils.copyProperties(userUpdateRequest, user);
        user.setBirthday(userUpdateRequest.getBirthday());
        boolean updated = this.updateById(user);
        ThrowUtils.throwIf(!updated, ResponseCodeEnum.SYSTEM_ERROR, "更新用户失败！");
        redisManager.deleteUserSession(user.getId());
        return true;
    }

    /**
     * 管理员根据id获取用户信息
     *
     * @param id 用户id
     * @return 用户信息
     */
    @Override
    public User getUserById(Long id) {
        ThrowUtils.throwIf(id <= 0, ResponseCodeEnum.INVALID_PARAMETER, "用户id错误！");
        User user = this.getById(id);
        ThrowUtils.throwIf(ObjUtil.isNull(user), ResponseCodeEnum.USER_NOT_FOUND, "用户不存在！");
        // 密码脱敏
        user.setUserPassword("****************");
        return user;
    }

    /**
     * 管理员分页获取用户列表
     *
     * @param queryRequest 查询条件
     * @return 用户列表
     */
    @Override
    public Page<UserVO> getUserList(UserQueryRequest queryRequest) {
        ThrowUtils.throwIf(queryRequest == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        int current = queryRequest.getCurrent();
        int pageSize = queryRequest.getPageSize();
        if (queryRequest.getId() != null) {
            queryRequest.setId(null);
        }
        Page<User> userPage = this.page(new Page<>(current, pageSize), this.getQueryWrapper(queryRequest));
        // copy一个空的Page<userVO>对象
        Page<UserVO> userVOPage = new Page<>(current, pageSize, userPage.getTotal());
        List<UserVO> userVOPageList = this.getUserVOList(userPage.getRecords());
        userVOPage.setRecords(userVOPageList);
        return userVOPage;
    }

    /**
     * 获取用户列表(脱敏)
     *
     * @param userList 用户列表
     * @return 脱敏后的用户列表
     */
    @Override
    public List<UserVO> getUserVOList(List<User> userList) {
        if (CollUtil.isEmpty(userList)) {
            return Collections.emptyList();
        }
        return userList.stream().map(this::getUserVO).collect(Collectors.toList());
    }

    /**
     * 密码加密
     *
     * @param password 密码
     * @return 加密后的密码
     */
    @Override
    public String encryptPassword(String password) {
        ThrowUtils.throwIf(StrUtil.isBlank(password), ResponseCodeEnum.INVALID_PARAMETER, "密码不能为空");
        // 加盐防止被暴力破解
        return DigestUtil.md5Hex(password + UserConstant.SALT);
    }

    /**
     * 获取用户信息(脱敏)
     *
     * @param user 用户信息
     * @return 脱敏后的用户信息
     */
    @Override
    public UserVO getUserVO(User user) {
        if (user == null) {
            return null;
        }
        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(user, userVO);
        return userVO;
    }

    /**
     * 分页查询条件封装
     *
     * @param queryRequest 查询参数
     * @return 查询条件
     */
    @Override
    public QueryWrapper<User> getQueryWrapper(UserQueryRequest queryRequest) {
        ThrowUtils.throwIf(queryRequest == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        Long id = queryRequest.getId(); // eq
        String userName = queryRequest.getUserName(); // like
        String userAccount = queryRequest.getUserAccount(); // eq
        String userProfile = queryRequest.getUserProfile(); // like
        String userRole = queryRequest.getUserRole(); // eq
        String sortField = queryRequest.getSortField(); // 排序字段
        String sortOrder = queryRequest.getSortOrder(); // 排序顺序
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(ObjUtil.isNotEmpty(id), "id", id);
        queryWrapper.eq(StrUtil.isNotBlank(userAccount), "user_account", userAccount);
        queryWrapper.eq(StrUtil.isNotBlank(userRole), "user_role", userRole);
        queryWrapper.like(StrUtil.isNotBlank(userName), "user_name", userName);
        queryWrapper.like(StrUtil.isNotBlank(userProfile), "user_profile", userProfile);
        queryWrapper.orderBy(StrUtil.isNotBlank(sortField), sortOrder.equals("ascend"), sortField);
        return queryWrapper;
    }

    /**
     * 判断是否是管理员
     *
     * @param user 用户
     * @return 判断是否是管理员
     */
    @Override
    public boolean isAdmin(User user) {
        if (ObjUtil.isEmpty(user)) {
            throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        }
        return UserRoleEnum.ADMIN.getValue().equals(user.getUserRole());
    }
}
